/**
 * 
 */
package com.google.code.jkippt;

import java.util.Collections;
import java.util.Iterator;
import java.util.Map;

import com.google.code.jkippt.http.APIClient;
import com.google.code.jkippt.http.ParametersBuilder;
import com.google.code.jkippt.http.ResourceEndpointUrlFactory;
import com.google.code.jkippt.http.paging.PageIterator;
import com.google.code.jkippt.http.paging.PagedResultItemIterator;
import com.google.code.jkippt.parser.PageParserBuilder;
import com.google.code.jkippt.parser.Parser;
import com.google.code.jkippt.query.ClipQuery;
import com.google.code.jkippt.resource.Clip;
import com.google.code.jkippt.resource.Comment;
import com.google.code.jkippt.resource.User;

import static com.google.code.jkippt.http.ParametersBuilder.*;

/**
 * @author "Federico De Faveri defaveri@gmail.com"
 *
 */
public class Clips extends KipptEndpoint {
	
	public static final String CLIP_ENDPOINT_NAME = "clips";
	
	protected static final String QUERY = "q";
	protected static final String FEED = "feed";
	protected static final String FAVORITES = "favorites";
	protected static final String COMMENTS = "comments";
	protected static final String LIKES = "likes";
	protected static final String SEARCH = "search";
	protected static final String INCLUDE_DATA = "include_data";
	protected static final String[] INCLUDE_LABELS = new String[]{"list","via","media"};
	
	protected ResourceEndpoint<Clip> clipsEndpoint;

	/**
	 * @param client
	 * @param parser
	 */
	protected Clips(APIClient client, Parser parser) {
		super(client, parser, CLIP_ENDPOINT_NAME);
		clipsEndpoint = new ResourceEndpoint<Clip>(client, parser, endpointUrlFactory, Clip.class);
	}
	
	/**
	 * Gets {@link User}'s {@link Clip}s, both public and private.
	 * @return the retrieved {@link Clip}s
	 * @throws JKipptException if an error occurs.
	 */
	public Iterator<Clip> getAll() throws JKipptException
	{
		return clipsEndpoint.getAll();
	}
	
	/**
	 * Gets all available {@link Clip}s using the specified parameters.
	 * @param query the retrieving parameters.
	 * @return the retrieved {@link Clip}s.
	 * @throws JKipptException if an error occurs.
	 */
	public Iterator<Clip> get(ClipQuery query) throws JKipptException
	{
		Map<String, String> parameters = query.toParameters();
		return clipsEndpoint.query(parameters);
	}
	
	/**
	 * Gets user's feed, including clips from followed users and lists.
	 * @return the retrieved {@link Clip}s.
	 * @throws JKipptException if an error occurs.
	 */
	public Iterator<Clip> getFeed() throws JKipptException
	{
		return clipsEndpoint.query(FEED, ResourceEndpointUrlFactory.NO_PARAMETERS);
	}	
	
	/**
	 * Gets user's feed, including clips from followed users and lists.
	 * @param query the retrieving parameters.
	 * @return the retrieved {@link Clip}s.
	 * @throws JKipptException if an error occurs.
	 */
	public Iterator<Clip> getFeed(ClipQuery query) throws JKipptException
	{
		Map<String, String> parameters = query.toParameters();
		return clipsEndpoint.query(FEED, parameters);
	}
	
	/**
	 * Gets user's favorites. This will return all favorites, both public and private.
	 * @return the retrieved {@link Clip}s.
	 * @throws JKipptException if an error occurs.
	 */
	public Iterator<Clip> getFavorites() throws JKipptException
	{
		return clipsEndpoint.query(FAVORITES, ResourceEndpointUrlFactory.NO_PARAMETERS);
	}	
	
	/**
	 * Gets user's favorites. This will return all favorites, both public and private.
	 * @param query the retrieving parameters.
	 * @return the retrieved {@link Clip}s.
	 * @throws JKipptException if an error occurs.
	 */
	public Iterator<Clip> getFavorites(ClipQuery query) throws JKipptException
	{
		Map<String, String> parameters = query.toParameters();
		return clipsEndpoint.query(FAVORITES, parameters);
	}
	
	/**
	 * Gets the specified {@link Clip}.
	 * @param id the {@link Clip} id.
	 * @return the retrieved {@link Clip}.
	 * @throws JKipptException if an error occurs.
	 */
	public Clip get(String id) throws JKipptException
	{
		return clipsEndpoint.get(id);
	}	
	
	/**
	 * Gets the specified {@link Clip}.
	 * @param id the {@link Clip} id.
	 * @param includeList to include the List.
	 * @param includeVia to include the Via.
	 * @param includeMedia to include the media.
	 * @return the retrieved {@link Clip}.
	 * @throws JKipptException if an error occurs.
	 */
	public Clip get(String id, boolean includeList, boolean includeVia, boolean includeMedia) throws JKipptException
	{
		ParametersBuilder builder = new ParametersBuilder();
		builder.add(INCLUDE_DATA, values(includeList, includeVia, includeMedia), INCLUDE_LABELS);
		String endpoint = endpointUrlFactory.buildEndpointUrl(id, builder.build());
		return clipsEndpoint.getFromEndpoint(endpoint);
	}
	
	/**
	 * Gets all the {@link Comment}s for the specified clip.
	 * @param id the {@link Clip} id.
	 * @return the retrieved comments.
	 * @throws JKipptException if an error occurs.
	 */
	public Iterator<Comment> getComments(String id) throws JKipptException
	{
		String firstPageEndPoint = endpointUrlFactory.buildEndpointUrl(id, COMMENTS);
		PageParserBuilder<Comment> parserBuilder = parser.getPageParserBuilder(Comment.class);
		PageIterator<Comment> pager = new PageIterator<Comment>(client, parserBuilder, firstPageEndPoint);
		return new PagedResultItemIterator<Comment>(pager);
	}
	
	/**
	 * Gets all the {@link User}s that have liked the clip.
	 * @param id the {@link Clip} id.
	 * @return the retrieved users.
	 * @throws JKipptException if an error occurs.
	 */
	public Iterator<User> getLikes(String id) throws JKipptException
	{
		String firstPageEndPoint = endpointUrlFactory.buildEndpointUrl(id, LIKES);
		PageParserBuilder<User> parserBuilder = parser.getPageParserBuilder(User.class);
		PageIterator<User> pager = new PageIterator<User>(client, parserBuilder, firstPageEndPoint);
		return new PagedResultItemIterator<User>(pager);
	}
	
	/**
	 * Search the available {@link Clip}s using the specified query.
	 * @param query the search term.
	 * @return the retrieved results.
	 * @throws JKipptException if an error occurs.
	 */
	public Iterator<Clip> search(String query) throws JKipptException
	{
		return clipsEndpoint.query(SEARCH, Collections.singletonMap(QUERY, query));
	}
	
	/**
	 * Search the available {@link Clip}s using the specified parameters.
	 * @param query the retrieving parameters.
	 * @return the query result.
	 * @throws JKipptException if an error occurs.
	 */
	public Iterator<Clip> search(String query, boolean includeList, boolean includeVia, boolean includeMedia) throws JKipptException
	{
		ParametersBuilder builder = new ParametersBuilder();
		builder.add(QUERY, query);
		builder.add(INCLUDE_DATA, values(includeList,  includeVia, includeMedia), INCLUDE_LABELS);
		return clipsEndpoint.query(SEARCH, builder.build());
	}
	
	/**
	 * Adds a new {@link Clip} with the specified url.
	 * @param url the {@link Clip} url.
	 * @return the created {@link Clip}.
	 * @throws JKipptException if an error occurs.
	 */
	public Clip add(String url) throws JKipptException
	{
		Clip clip = new Clip(url);
		return add(clip);
	}
	
	/**
	 * Adds a new {@link Clip}. The {@link Clip} have to be new.
	 * @param clip the {@link Clip} to add.
	 * @return the added {@link Clip}.
	 * @throws JKipptException
	 */
	public Clip add(Clip clip) throws JKipptException
	{
		return clipsEndpoint.add(clip);
	}
	
	/**
	 * Updates the specified {@link Clip}.
	 * @param clip the {@link Clip} to update.
	 * @return the updated {@link Clip}.
	 * @throws JKipptException
	 */
	public Clip update(Clip clip) throws JKipptException
	{
		return clipsEndpoint.update(clip);
	}
	
	/**
	 * Adds a new {@link Comment} to the specified {@link Clip}.
	 * @param id the {@link Clip} id.
	 * @param comment the {@link Comment} to add.
	 * @return the updated {@link Comment}.
	 * @throws JKipptException if an error occurs.
	 */
	public Comment addComment(String id, Comment comment) throws JKipptException
	{
		String endpoint = endpointUrlFactory.buildEndpointUrl(id, COMMENTS);
		String json = parser.toJson(comment);
		String response = client.post(endpoint, json);
		return parser.parse(response, Comment.class);
	}
	
	/**
	 * Likes the specified {@link Clip}.
	 * @param id the {@link Clip} id.
	 * @throws JKipptException if an error occurs.
	 */
	public void like(String id) throws JKipptException
	{
		String endpoint = endpointUrlFactory.buildEndpointUrl(id, LIKES);
		client.post(endpoint, "");
	}
	
	/**
	 * Favorites the specified {@link Clip}.
	 * @param id the {@link Clip} id.
	 * @throws JKipptException if an error occurs.
	 */
	public void favorite(String id) throws JKipptException
	{
		String endpoint = endpointUrlFactory.buildEndpointUrl(id, FAVORITES);
		client.post(endpoint, "");
	}
	
	/**
	 * Deletes the specified {@link Clip}.
	 * @param id the {@link Clip} id.
	 * @throws JKipptException if an error occurs.
	 */
	public void delete(String id) throws JKipptException
	{
		clipsEndpoint.delete(id);
	}

	/**
	 * Deletes the specified {@link Comment} from the specified {@link Clip}.
	 * @param id the clip id.
	 * @param commentId the comment id.
	 * @throws JKipptException if an error occurs.
	 */
	public void deleteComment(String id, String commentId) throws JKipptException
	{
		String endpoint = endpointUrlFactory.buildEndpointUrl(id, COMMENTS,commentId);
		client.delete(endpoint);
	}
	
	/**
	 * Unfavorites the specified {@link Clip}.
	 * @param id the {@link Clip} id.
	 * @throws JKipptException if an error occurs.
	 */
	public void unfavorite(String id) throws JKipptException
	{
		String endpoint = endpointUrlFactory.buildEndpointUrl(id, FAVORITES);
		client.delete(endpoint);
	}
	
	/**
	 * Unlikes the specified {@link Clip}.
	 * @param id the {@link Clip} id.
	 * @throws JKipptException if an error occurs.
	 */
	public void unlike(String id) throws JKipptException
	{
		String endpoint = endpointUrlFactory.buildEndpointUrl(id, LIKES);
		client.delete(endpoint);
	}

}
